module addr_unit
#(
  parameter DFT_POINTS = 8
)(
  //OUTPUTS
  output [clogb2(DFT_POINTS/2) - 1:0]addr_bank0,          //Address to Memory Bank 0
  output [clogb2(DFT_POINTS/2) - 1:0]addr_bank1,          //Address to Memory Bank 1
  output reg [clogb2(DFT_POINTS/2) - 1:0]addr_angle,      //Twiddle factor index
  output wire ready,                                      //Last Stages is completed
  output reg exc_sel0,                                    //Select Signal for Butterfly exchange 0
  output reg exc_sel1,                                    //Select Signal for Butterfly exchange 1
  //INPUTS
  input enable,                                           //Enables generation to next address
  //input restart,                                        //Restart address generation unit
  input clk,
  input rst_n
);

//Ceiling of the log-base 2 of a number
function integer clogb2;
  input [31:0] value;
  reg div2;
  begin
    div2 = value%2;
 	  for (clogb2 = 0; value>0; clogb2=clogb2+1)
      value = value>>1;
    clogb2 = (div2) ? clogb2 : clogb2 - 1;
  end
endfunction

localparam DFT_BITS     = clogb2(DFT_POINTS/2);
localparam STAGE_NUM    = clogb2(DFT_POINTS);
localparam STAGE_BITS   = clogb2(STAGE_NUM);
localparam COUNTER_SIZE = DFT_BITS + STAGE_BITS;

reg  [COUNTER_SIZE - 1:0] counter;
wire [STAGE_BITS   - 1:0] stage_cnt;
wire [DFT_BITS     - 1:0] butt_cnt;
reg  [DFT_BITS - 1    :0] sft_reg;//DFT_BITS:0


assign stage_cnt = counter[COUNTER_SIZE - 1: COUNTER_SIZE - STAGE_BITS];
assign butt_cnt  = counter[DFT_BITS - 1:0];
assign ready     = (stage_cnt == STAGE_NUM - 1 && butt_cnt == {DFT_BITS{1'b1}});

always @(posedge clk, negedge rst_n)
  begin
    if(!rst_n)
      counter <= {COUNTER_SIZE{1'b0}};
    else
      if(enable)
        counter <= (ready) ? {COUNTER_SIZE{1'b0}} : counter + 1;  
  end

  //Shift Register for control of addr_bank1
  always @(posedge clk, negedge rst_n)
    begin : SFT_REG
      integer i;
      if(!rst_n)
        sft_reg <= {DFT_BITS{1'b0}};
      else
        if(enable)
          if(ready)
            sft_reg <= {DFT_BITS{1'b0}};//{{(DFT_BITS-1){1'b0}}, 1'b1};
          else
            if(butt_cnt == {DFT_BITS{1'b1}})
              begin
                for(i=0; i < DFT_BITS; i = i + 1)//i <=
                  begin
                    if(!i)
                      sft_reg[i] <= 1'b1;
                    else
                      sft_reg[i] <= sft_reg[i - 1];
                  end  
              end    
    end
  
  //Bank 0: address definition
  assign addr_bank0 = butt_cnt;
  
  //Bank 1: address definition
  generate
    genvar i;
    for(i = 0; i < DFT_BITS; i = i + 1)
      assign addr_bank1[i] = (sft_reg[DFT_BITS - 1 - i]) ? ~butt_cnt[i] : butt_cnt[i];//DFT_BITS -i   
  endgenerate
  
  //Exchange Selector
  always @(*)
    begin : EXC_SEL
      integer i;
      exc_sel0 = 1'b0;
      exc_sel1 = 1'b1;
      if(stage_cnt == 0)
        begin
          exc_sel0 = 1'b0;
          exc_sel1 = butt_cnt[DFT_BITS - 1];
        end
      else
        if(stage_cnt == STAGE_NUM - 1)
          begin
            exc_sel0 = butt_cnt[0];
            exc_sel1 = 1'b0;
          end
        else
          for(i = 1; i  < STAGE_NUM; i = i + 1)
            begin
              if(stage_cnt == i)
                begin
                  exc_sel0 = butt_cnt[DFT_BITS - i];
                  exc_sel1 = butt_cnt[DFT_BITS - 1 - i];
                end
            end
    end 
    
  //Address of Twiddle Factor
  always @(*)
    begin : TWIDDLE_MUX
      integer i, mux;
      addr_angle = {DFT_BITS{1'b0}};
      for(mux = 0; mux < DFT_BITS; mux = mux + 1)//Define DFT_BITS multiplexors
        begin
          for(i = 0; i < DFT_BITS; i = i + 1)//Define DFT_BITS inputs for each mux
            begin
              if(stage_cnt == i)
                addr_angle[mux] = (mux - i < 0) ? 1'b0 : butt_cnt[mux - i];
            end
        end 
    end
endmodule
